// 基础类型
let age : number = 23

const personName : string = '托合提如苏力'

const male : boolean = true

// any 类型

let key = []

// 数组
let num : number[] = [1, 2, 3, 4]

// 元组 tuple

let user:[number , number , string] = [1 , 2 , '托合提如苏力']

/**
 * enum类型 是常量，所以写的时候必须都是大写
 */

const SMALL = 1
const MEDIUM = 2
const LARGE = 3

/**
 * const 方法来指定变量值值和在enum 类型的变量名称里面的值不一样。
 * enum类型的值，如果没有被指定那就0开始给指定值
 */
enum Size {
    SMALL = 5,
    MEDIUM,
    LARGE
}

console.log(Size.LARGE , LARGE)  // 结果为2 ， 3

/**
 * enum 类型的变量名还能可以能用类型。
 */

const MySize : Size = Size.LARGE

console.log(MySize)


// 函数

function MyIncome (income : number) {
    if (income >= 5000) {
        return income * 0.03;
    }
    return 0
}

const flag = true

function MyIncomes ( income : number) : string {
    // const flag = true  //作用于里面 如果有没有被用到的参数的话给个提醒你没有被用该参数。
    if ( income >= 5000) {
        return `交的税费：${income * 0.03}`;
    }
    return '返回的值为字符串'
}

// 如果是是参数不是一个的话，那就下面的额方式写
/**
 *
 * @param wages
 * @param fees
 * @constructor
 * 有wages ， fees 这两种参数时我们,必须给两种参数不然会报错
 * 如果是我们只有工作没有交学费的话 Fees 函数的参数这样的改
 * Fees(wages: number , fees : number = 0)
 * fess: number = 0 表示fees的学费的默认值为 0 这样不会报错的。
 * 在参数里面不能使用 ？ 这个符合来判断，是因为产生一个undefined。
 */
function Fees (wages: number , fees : number = 0) : string {
    const rest: number = wages - fees;
    if (rest >= 5000) {
        return `我剩下的钱：${rest}`
    }
    return '不用提交学费啦'
}

console.log(Fees(6000 , 1200))

// 对象

const Student = {
    id : 1,
}

// Student.name = '苏力'  // 会报错，使用为该对象的类型指定为 number 使用无法添加name值

// 如果是添加name值的话下面这样添加就可以。

const student : {
    id : number,
    name : string
} = {
    id : 1,
    name : '苏力'
}

student.id = 5

console.log(student) // 这样能打印student对象的值。  值为{ id: 5, name: '苏力' }

// 如果是我们可能有时候用有时候不用的参数，这样设置就可以。但不要设置重要信息身上

const pupils : {
     readonly id : number
    name : string
    gander ?: string
} = {
    id : 1,
    name : '苏力'
}

pupils.gander = '男'
console.log(pupils)  // 打印出来的值为 { id: 1, name: '苏力', gander: '男' }

const person : {
    id : number
    name : string
    gander : string
} = {
    id :  1,
    name : '苏力',
    gander : '男',
}

// function GetAge (age : number) : number {
//     if (age >= 18) {
//         return age
//     }
//     return age
// }

// 类型别名

type student0 = {
    id : number
    name : string
}

const student1 : student0 = {
    id : 2 ,
    name : '苏力'
}

const person2 : student0 = {
    id : 3 ,
    name : '苏力'
}

function person0 (age : number | string):number | string  {
    if (typeof age === "number" && age >= 18) {
        return `我终于成年人了`
    } else  {
        return 0
    }
}

console.log(person0( 20))   // 只打印出  我终于成年人了
console.log(person0( 10))   // 打印出 0
console.log(person0( '20'))

// 交叉类型
type bing = {
    id : number
    age: number
}

type name = {
    names : string
    evaluation(scores:number) : string
}

let textBox : bing & name = {
    id : 1,
    names : '托合提如苏力',
    age : 23,
    evaluation(scores) : string{
        if (scores < 60) {
            return '未通过'
        }else if (scores >= 60 && scores < 80) {
            return '良好'
        }else {
            return '优秀'
        }
}
}

console.log(textBox.evaluation(10))  // 未通过
console.log(textBox.evaluation(60))  // 良好
console.log(textBox.evaluation(90))  // 优秀

// 字面量

// let Direction : 'left' | 'right' | 'top' | 'button' =  'left'

type direction = 'left' | 'right' | 'top' | 'button'

let Direction : direction = 'right'

// 可选链操作符
type Student = {
    birthday : Date
}

function GetStudent(id : number) : Student | null {
    return id === 0 ? null : {birthday : new Date()}
}

const num1 = GetStudent(10)
const num2 = GetStudent(0)

if (num2 == undefined) {
    console.log('GetStudent() 函数返回值为undefined')
}
// console.log(num1?.birthday)
console.log(num1?.birthday.getFullYear())

// 空值合并操作符

const speed : number | null = null

const bike: {speed : number} = {
    // speed : speed ? speed : 15
    // 或者
    speed : speed ?? 15
}

// 不知道该参数什么样的类型的时候使用unknown

function render(document : unknown) {
//     不知道document的类型是什么的时候判断的形式执行代码
    if (typeof document === 'string') {
        console.log('document是字符串')
    }

    if (document instanceof Document) {
    //     能打印出DOM的函数
        console.log(document.body)
    }
}

// never类型

// function test() : never {
//     /*
//         whire(true) {
//             这个是死循环
//         }
//     */
//
// // 还有一个是
//     throw new Error('错误')
// }


/**
 * Account 是账户的意思
 * 封装类
 */
class Account {
    readonly id : number         // id
    name : string       // 用户
    private balance : number    // 余额

    constructor(id: number, name: string, balance: number) {
        this.id = id;
        this.name = name;
        this.balance = balance;
    }

    /**
     * amount 是金额
     * Savers 是存钱
     */

    Savers(amount : number) : void {
        if ( amount < 0) {
            throw new Error('非法数值')
        }
        this.balance += amount
    }

    Outlay(amount : number) : void  {
        if (this.balance < amount) {
            throw new Error('余额不足')
        }
        this.balance -= amount;
    }

    get balances() : number {
        return this.balance
    }

    set balances( value : number) {
        this.balance = value
    }
}
// 实例化对象
const account  = new Account(1, '托合提如苏力' , 0)
// 调用对象
account.Savers(60)      // 存钱50
account.Outlay(30)      // 支出30
account.balances = 24
console.log("最后的结果为：" + account.balances)   // 最后的结果为：30

class test extends Account {

}


class autograph  {
    // name , age
    [sign : string] : string
}

const AutoGraph = new autograph();

AutoGraph.name = '苏力';
// AutoGraph.age = 12  不行是因为key也是string ，key的值也是string。

console.log(AutoGraph) // 结果为：autograph { name: '苏力' }

class Car {
    private static _activeCar : number = 0

    start() : number {
        return Car._activeCar ++;
    }

    stop() : number {
        return Car._activeCar --;
    }

    static get activeCar() {
        return Car._activeCar;
    }
}

const car1 = new Car();
const car2 = new Car();
car1.start()
console.log(Car.activeCar)  // 结果为：1
car2.start()
console.log(Car.activeCar)  // 结果为：2

// Car._activeCar = 1 // 会报错，不能被修改、

// 继承

class Person {
    firsName : string
    lastName : string

    constructor(firsName: string, lastName: string) {
        this.firsName = firsName;
        this.lastName = lastName;
    }

    get FullName() : string {
        return "lastName" + "firsName"
    }

    walk() {
        console.log(this.FullName + 'is walking')
    }

    talk() {
        console.log(this.FullName + 'is talking')
    }
}

class Student5 extends Person{
    id : number

    constructor(id : number,firsName: string, lastName: string) {
        super(firsName, lastName);
        this.id = id
    }

    study() {
        console.log(this.FullName + 'is studying')
    }
}

class Teacher extends Person{
    id : number
    constructor(id : number, firsName: string, lastName: string) {
        super(firsName,lastName)
        this.id = id
    }
    teach() {
        console.log(this.FullName + 'is teaching')
    }

    override get FullName() {
        return this.lastName + '老师'
    }
}

const teacherName = new Teacher(101, '辉' , '张')
const studentName = new Teacher(1, '薄' , '鹏')

console.log(teacherName.FullName)
console.log(studentName)

// 抽象类 和 抽象方法
abstract class Sheep {
    constructor(public color : string) {
    }

    abstract render() : void; // 使用抽象方法的时候实现过程不能被写。{这个符合不能写}
}

class Circle extends Sheep {
    constructor(public radius : number, color : string) {
        super(color);
    }

    override render() {
        console.log(`渲染一个半径为${this.radius}，颜色为${this.color}的圆形`);
    }
}

const circle = new Circle(15, "紫色")
// 父类的实例化
// const sheep = new Sheep('hello')  // 会报错，是因为Sheep对象被成抽象类，抽象类不能实例化。
circle.render() // 结果为：渲染一个半径为15，颜色为紫色的圆形

// 接口

interface Calender {

    _name : string;
    addEvent():void
    removeEvent():void
}

interface CloudCalender extends Calender {
    sync() : void
}
class GoogleCalender implements CloudCalender {
    constructor(public _name : string) {
    }

    addEvent() : void {
    }

    removeEvent() {
    }

    sync() {
    }
}

let googleCalender = new GoogleCalender('hello')

// 泛型
/**
 * 我们需要使用一个变量的多个类型，这个时候我们使用的是泛型。
 */
//
// class KeyValues<K,V> {
//
//     constructor(public key : K,public value : V) {
//     }
// }
//
// let storage = new KeyValues<number,string>(1, "依力")
// let storage1 = new KeyValues<number, { name : string , role : string }>(1, {name : "苏力" , role : "管理员"})
// let storage2 = new KeyValues(1, "依力")
//
// function Student7<t>(value : t) {
//     return [value];
// }
//
// let student7 = Student7("hello")
// let student8 = Student7(1)
//
// class Person2 {
//     Student9<v> (value : v) {
//         return [value]
//     }
// }
//
// let perstin = new Person2();
// perstin.Student9("hello")
// perstin.Student9(1)

// 泛型接口
// interface PageResult<t> {
//     paging : Paging,
//     Data : t[]
// }
//
// type Paging = {
//     page : number;
//     size : number;
//     total : number
// }

// type User = {
//     id : number;
//     name : string;
// }

// let pageResult : PageResult<User> = {
//     // paging : {
//     //     id : 1;
//     //     size : 20;
//     //     total : 2;
//     // },
//
//     Data : [{ id : 1 , name : "依力"}]
// }

// class Store<T> {
//     protected Objects : T[] = []
//
//     add(obj : T) {
//         this.Objects.push(obj)
//     }
// }
//
// // 传入泛型类型参数
// class StoreValue<T> extends Store<T> {
//     values() {}
// }
//
// class SearchableStors<T extends {name : string}> extends Store<T> {
//     find(name : string) : T | undefined {
//         return this.Objects.find(item=> item.name === name)
//     }
// }